// 导入必要的Java库
import javax.swing.*; // Swing组件库，用于构建GUI界面
import javax.script.ScriptEngine; // 脚本引擎接口，用于计算数学表达式
import javax.script.ScriptEngineManager; // 脚本引擎管理器，用于获取脚本引擎实例
import javax.script.ScriptException; // 脚本异常类，处理脚本执行错误
import java.awt.*; // AWT图形库，提供基础图形功能
import java.awt.event.*; // AWT事件库，处理用户交互事件
import java.awt.image.BufferedImage; // 缓冲图像类，用于图像处理
import java.io.File; // 文件类，用于文件操作
import java.text.SimpleDateFormat; // 简单日期格式类，格式化日期时间
import java.util.Date; // 日期类，处理日期时间数据
import javax.sound.sampled.*; // 声音采样库，处理音频
import javax.imageio.ImageIO; // 图像IO库，读写图像文件
import javax.swing.filechooser.FileNameExtensionFilter; // 文件过滤器，限制文件选择类型

// 主类继承JFrame并实现ActionListener接口
public class B extends JFrame implements ActionListener {
    // 声明组件变量
    private JPanel north, center; // 顶部面板(显示文本框)和中间面板(显示按钮)
    private JTextField field; // 文本框，显示计算结果和用户输入
    private JButton[] btns; // 按钮数组，包含所有计算器按钮
    private Clip buttonSound; // 音频剪辑对象，存储按钮点击音效
    private BufferedImage backgroundImage; // 缓冲图像对象，存储背景图片
    private JMenuBar menuBar; // 菜单栏对象
    private JMenuItem changeWallpaperItem; // "更换壁纸"菜单项
    private JMenuItem resetWallpaperItem; // "重置壁纸"菜单项
    private Timer timeUpdateTimer; // 定时器对象
    private boolean isTimeDisplaying = false; // 标记是否正在显示时间

    // 构造函数
    public B() {
        setTitle("Calculator"); // 设置窗口标题为"Calculator"
        setSize(700, 700); // 设置窗口大小为700x700像素
        setDefaultCloseOperation(EXIT_ON_CLOSE); // 设置关闭窗口时退出程序
        
        try {
            // 加载按钮音效文件
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(
                new File("button.wav")); // 创建音频输入流，从"button.wav"文件读取
            buttonSound = AudioSystem.getClip(); // 获取音频剪辑实例 getClip接口
            buttonSound.open(audioInputStream); // 打开音频流并加载到剪辑
            
            // 尝试加载默认背景图片
            try {
                backgroundImage = ImageIO.read(new File("壁纸1.jpg")); // 从"壁纸1.jpg"文件读取图片
            } catch (Exception e) {
                // 如果默认壁纸不存在，创建一个1x1像素的白色图像
                backgroundImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
                Graphics2D g2d = backgroundImage.createGraphics(); // 创建图形上下文
                g2d.setColor(Color.WHITE); // 设置颜色为白色
                g2d.fillRect(0, 0, 1, 1); // 填充整个图像
                g2d.dispose(); // 释放图形资源
            }
        } catch (Exception e) {
            System.out.println("Error loading resources: " + e.getMessage()); // 打印资源加载错误信息
        }
        
        initComponent(); // 初始化界面组件
        createMenuBar(); // 创建菜单栏
        setLocationRelativeTo(null); // 设置窗口居中显示
        setVisible(true); // 显示窗口
    }

    // 创建菜单栏方法
    private void createMenuBar() {
        menuBar = new JMenuBar(); // 创建新的菜单栏
        
        // 创建"设置"菜单
        JMenu settingsMenu = new JMenu("自定义壁纸"); // 创建菜单标签为"自定义壁纸"
        
        // 创建"更换壁纸"菜单项
        changeWallpaperItem = new JMenuItem("更换壁纸"); // 创建菜单项
        changeWallpaperItem.addActionListener(e -> changeWallpaper()); // 添加点击事件监听
        
        // 创建"重置壁纸"菜单项
        resetWallpaperItem = new JMenuItem("重置默认壁纸"); // 创建菜单项
        resetWallpaperItem.addActionListener(e -> resetWallpaper()); // 添加点击事件监听
        
        // 将菜单项添加到菜单
        settingsMenu.add(changeWallpaperItem); // 添加"更换壁纸"项
        settingsMenu.add(resetWallpaperItem); // 添加"重置壁纸"项
        
        // 将菜单添加到菜单栏
        menuBar.add(settingsMenu); // 将"设置"菜单添加到菜单栏
        
        // 设置窗口的菜单栏
        this.setJMenuBar(menuBar); // 将菜单栏添加到窗口
    }

    // 更换壁纸方法
    private void changeWallpaper() {
        JFileChooser fileChooser = new JFileChooser(); // 创建文件选择器
        
        // 设置文件过滤器，只显示图片文件
        FileNameExtensionFilter filter = new FileNameExtensionFilter(
            "图片文件", "jpg", "jpeg", "png", "gif", "bmp"); // 定义支持的图片格式
        fileChooser.setFileFilter(filter); // 为文件选择器设置过滤器
        
        // 显示文件选择对话框
        int result = fileChooser.showOpenDialog(this); // 显示打开文件对话框
        
        if (result == JFileChooser.APPROVE_OPTION) { // 如果用户选择了文件
            File selectedFile = fileChooser.getSelectedFile(); // 获取选择的文件
            try {
                // 加载新壁纸
                BufferedImage newImage = ImageIO.read(selectedFile); // 读取图片文件
                if (newImage != null) { // 如果成功读取
                    backgroundImage = newImage; // 更新背景图片
                    repaint(); // 重绘窗口以显示新壁纸
                }
            } catch (Exception e) {
                // 显示错误消息对话框
                JOptionPane.showMessageDialog(this, "无法加载图片: " + e.getMessage(), 
                    "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // 重置壁纸方法
    private void resetWallpaper() {
        try {
            // 尝试加载默认壁纸
            backgroundImage = ImageIO.read(new File("壁纸1.jpg")); // 读取默认壁纸文件
            repaint(); // 重绘窗口
        } catch (Exception e) {
            // 如果默认壁纸不存在，创建白色背景
            backgroundImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = backgroundImage.createGraphics();
            g2d.setColor(Color.WHITE);
            g2d.fillRect(0, 0, 1, 1);
            g2d.dispose();
            repaint(); // 重绘窗口
            
            // 显示提示消息
            JOptionPane.showMessageDialog(this, "默认壁纸不存在，已重置为白色背景", 
                "提示", JOptionPane.INFORMATION_MESSAGE);
        }
    }

    // 初始化组件方法
    private void initComponent() {
        // 创建主面板(带背景图片)，使用匿名内部类重写paintComponent方法
        JPanel mainPanel = new JPanel(new BorderLayout()) {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g); // 调用父类绘制方法
                if (backgroundImage != null) {
                    // 绘制背景图片(缩放适应窗口大小)
                    g.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
                }
            }
        };

        // 初始化顶部和中间面板
        north = new JPanel(); // 创建顶部面板
        center = new JPanel(); // 创建中间面板
        center.setOpaque(false); // 设置中间面板透明
        north.setOpaque(false); // 设置顶部面板透明
        
        // 初始化文本框
        field = new JTextField(); // 创建文本框
        field.setPreferredSize(new Dimension(700, 150)); // 设置首选大小
        field.setEditable(false); // 禁止直接编辑
        field.setFont(new Font("SansSerif", Font.BOLD, 35)); // 设置字体
        field.setBackground(new Color(240, 240, 240, 200)); // 设置半透明背景
        field.setBorder(BorderFactory.createLineBorder(new Color(100, 100, 100), 2)); // 设置边框

        // 按钮标签数组
        String[] str = new String[]{
            "7", "8", "9", "+",  
            "4", "5", "6", "-",  
            "1", "2", "3", "×", 
            "0", ".", "=", "÷",  
            "C", "B", "T", "S"   // 第五行按钮(清除、退格、时间、日期)
        };

        // 初始化按钮数组
        btns = new JButton[str.length]; // 创建按钮数组
        for (int i = 0; i < btns.length; i++) {
            btns[i] = new JButton(str[i]); // 创建按钮并设置文本
            btns[i].setFont(new Font("SansSerif", Font.BOLD, 35)); // 设置按钮字体
            btns[i].setBackground(new Color(220, 220, 220, 0)); // 设置透明背景0-255 0完全透明
            btns[i].setBorder(BorderFactory.createRaisedBevelBorder()); // 设置3D边框
            btns[i].setFocusPainted(false); // 禁用焦点绘制(避免点击时出现虚线框)
            btns[i].setOpaque(true); // 设置不透明(与透明度配合)
            
            // 添加鼠标悬停效果
            btns[i].addMouseListener(new MouseAdapter() {
                public void mouseEntered(MouseEvent evt) {
                    JButton button = (JButton) evt.getSource();
                    button.setBackground(new Color(200, 200, 255)); // 鼠标进入时改变颜色 参数分别是红绿蓝
                }
                
                public void mouseExited(MouseEvent evt) {
                    JButton button = (JButton) evt.getSource();
                    button.setBackground(new Color(220, 220, 220)); // 鼠标离开时恢复颜色
                }
            });
        }

        // 设置面板布局
        north.setLayout(new BorderLayout()); // 顶部面板使用边界布局
        center.setLayout(new GridLayout(5, 4, 5, 5)); // 中间面板使用5行4列的网格布局，间距5像素
        north.add(field, BorderLayout.CENTER); // 将文本框添加到顶部面板中央
        
        // 将按钮添加到中间面板并添加事件监听
        for (JButton btn : btns) {
            center.add(btn); // 添加按钮到面板
            btn.addActionListener(this); // 添加点击事件监听
        }

        // 将子面板添加到主面板
        mainPanel.add(north, BorderLayout.NORTH); // 顶部面板放在主面板北部
        mainPanel.add(center); // 中间面板放在主面板中部(默认CENTER)
        add(mainPanel); // 将主面板添加到窗口
    }

    // 按钮文本处理方法
    private void setBtnText(String text) {
        String currentText = field.getText(); // 获取当前文本框内容
        
        switch (text) {
            case "C": // 清除按钮
                field.setText(""); // 清空文本框
                playSound(); // 播放音效
                break;
            case "T": // 时间按钮
                if (isTimeDisplaying) {
                    // 如果正在显示时间，停止定时器并清空文本框
                    if (timeUpdateTimer != null) {
                        timeUpdateTimer.stop(); // 停止定时任务
                    }
                    isTimeDisplaying = false;
                    field.setText(""); // 清空文本框
                } else {
                    // 如果未显示时间，启动定时器
                    isTimeDisplaying = true;
                    timeUpdateTimer = new Timer(1000, e -> { // 每隔1000ms（1秒）触发一次
                        SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
                        field.setText(timeFormat.format(new Date())); // 更新时间显示
                    });
                    timeUpdateTimer.start(); // 启动定时任务
                }
                playSound(); // 播放音效
                break;
            case "S": // 日期按钮
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 创建日期格式
                field.setText(dateFormat.format(new Date())); // 格式化当前日期并显示
                playSound();
                break;
            case "B": // 退格按钮
                if (currentText.length() != 0) {
                    // 删除最后一个字符
                    field.setText(currentText.substring(0, currentText.length() - 1));
                }
                playSound();
                break;
            case "=": // 等于按钮
                calculate(); // 执行计算
                playSound();
                break;
            case ".": // 小数点按钮
                if (currentText.isEmpty()) {//文本框为空
                    field.setText("0."); // 如果为空，自动补0.
                } else if (currentText.endsWith(".") || isLastCharOperator(currentText)) {
                    // 如果已有小数点或运算符，不做操作
                } else if (!hasDotInCurrentNumber(currentText)) {
                    field.setText(currentText + "."); // 添加小数点
                }
                playSound();
                break;
            case "+":
            case "-":
            case "×":
            case "÷": // 运算符按钮
                if (!currentText.isEmpty() && !isLastCharOperator(currentText)) {//检查非空 非末尾字符
                    field.setText(currentText + text); // 添加运算符
                }
                playSound();
                break;
            default: // 数字按钮(0-9)
                field.setText(currentText + text); // 添加数字
                playSound();
                break;
        }
    }

    // 检查最后一个字符是否是运算符
    private boolean isLastCharOperator(String text) {
        if (text.isEmpty()) return false; // 空字符串返回false
        char lastChar = text.charAt(text.length() - 1); // 获取最后一个字符
        return lastChar == '+' || lastChar == '-' || lastChar == '×' || lastChar == '÷';
    }

    // 检查当前数字是否已有小数点
    private boolean hasDotInCurrentNumber(String text) {
        int i = text.length() - 1; // 从字符串末尾开始
        while (i >= 0) {
            char c = text.charAt(i); // 获取当前字符
            if (c == '.') return true; // 找到小数点返回true
            if (c == '+' || c == '-' || c == '×' || c == '÷') break; // 遇到运算符停止
            i--;
        }
        return false; // 未找到小数点返回false
    }

    // 计算方法
    private void calculate() {
        String expression = field.getText(); // 获取表达式
        // 替换乘除符号为JavaScript可识别的符号
        expression = expression.replaceAll("×", "*").replaceAll("÷", "/");
        
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("javascript"); // 获取JavaScript引擎
        
        try {
            Object result = engine.eval(expression); // 执行计算
            field.setText(result.toString()); // 显示结果
        } catch (ScriptException e) {
            field.setText("Error"); // 计算错误显示"Error"
        }
    }

    // 播放音效方法
    private void playSound() {
        if (buttonSound != null) {
            buttonSound.setFramePosition(0); // 重置音效到开始位置
            buttonSound.start(); // 播放音效
        }
    }

    // 按钮点击事件处理
    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() instanceof JButton) {
            JButton btn = (JButton) e.getSource();
            
            // 按钮按下动画效果
            btn.setBorder(BorderFactory.createLoweredBevelBorder()); // 设置按下状态边框
            Timer timer = new Timer(100, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    btn.setBorder(BorderFactory.createRaisedBevelBorder()); // 恢复抬起状态边框
                    ((Timer)e.getSource()).stop(); // 停止计时器
                }
            });
            timer.setRepeats(false); // 不重复执行
            timer.start(); // 启动计时器
            
            setBtnText(btn.getText()); // 处理按钮文本
        }
    }

    // 主方法
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> { // 在事件分发线程中执行
            try {
                // 设置系统外观风格
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                e.printStackTrace(); // 打印外观设置错误信息
            }
            new B(); // 创建计算器实例
        });
    }
}